﻿// Copyright 2009 Mike Geise
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Falcon.Forums.Services
{
	using System.Collections.Generic;
	using Falcon.Core.Domain;
	using Falcon.Core.Domain.Services;
	using Falcon.Core.Extensions;
	using Falcon.Forums.Domain;
	using Falcon.Forums.Domain.Enums;
	using Falcon.Forums.Domain.Extensions;
	using Falcon.Forums.Domain.Repositories;
	using Falcon.Forums.Domain.Services;
	using Falcon.Forums.Domain.Values;
	using Roles = Falcon.Core.Domain.Roles;

	public class ForumPermissionService : IForumPermissionService
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="ForumPermissionService"/> class.
		/// </summary>
		/// <param name="forumPermissionRepository">The forum permission repository.</param>
		/// <param name="userRoleService">The user role service.</param>
		public ForumPermissionService(
			IForumPermissionRepository forumPermissionRepository, 
			IUserRoleService userRoleService)
		{
			this.ForumPermissionRepository = forumPermissionRepository;
			this.UserRoleService = userRoleService;
		}

		/// <summary>
		/// Gets or sets the forum permission repository.
		/// </summary>
		/// <value>The forum permission repository.</value>
		public IForumPermissionRepository ForumPermissionRepository
		{
			get; 
			private set;
		}

		/// <summary>
		/// Gets or sets the user role service.
		/// </summary>
		/// <value>The user role service.</value>
		public IUserRoleService UserRoleService
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets the forum permission by id.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public ForumPermission GetById(int id)
		{
			return this.ForumPermissionRepository.GetById(id);
		}

		/// <summary>
		/// Gets all the forums permissions.
		/// </summary>
		/// <returns></returns>
		public IList<ForumPermission> GetAll()
		{
			return this.ForumPermissionRepository.GetAll();
		}

		/// <summary>
		/// Gets all the forums permissions by the specified specification.
		/// </summary>
		/// <param name="specification">The specification.</param>
		/// <returns></returns>
		public IList<ForumPermission> GetAll(ForumPermissionSpecification specification)
		{
			return this.ForumPermissionRepository.GetAll(specification);
		}

		/// <summary>
		/// Gets the default forums permissions.
		/// </summary>
		/// <returns></returns>
		public IList<ForumPermission> GetDefault()
		{
			// note: this needs a major refactor
			// permissions
			var permissions = new List<ForumPermission>();

			// guests permissions
			var guests = new ForumPermission
			{
				Role = new UserRole { Title = Roles.Guests }
			};

			guests.Action = guests.Action
				.Add(ForumPermissionActions.View);

			guests.PostAction = guests.PostAction
				.Add(ForumPostPermissionActions.View)
				.Add(ForumPostPermissionActions.ViewAny);

			guests.TopicAction = guests.PostAction
				.Add(ForumTopicPermissionActions.View)
				.Add(ForumTopicPermissionActions.ViewAny);

			permissions.Add(guests);

			// users permissions
			var users = new ForumPermission
			{
				Role = new UserRole { Title = Roles.Users }
			};

			users.Action = users.Action
				.Add(ForumPermissionActions.View)
				.Add(ForumPermissionActions.Search);

			users.PostAction = users.PostAction
				.Add(ForumPostPermissionActions.View)
				.Add(ForumPostPermissionActions.ViewAny)
				.Add(ForumPostPermissionActions.ViewAttachment)
				.Add(ForumPostPermissionActions.Create)
				.Add(ForumPostPermissionActions.CreateAttachment)
				.Add(ForumPostPermissionActions.Update)
				.Add(ForumPostPermissionActions.DeleteAttachment);

			users.TopicAction = users.PostAction
				.Add(ForumTopicPermissionActions.View)
				.Add(ForumTopicPermissionActions.ViewAny)
				.Add(ForumTopicPermissionActions.Create)
				.Add(ForumTopicPermissionActions.CreatePoll)
				.Add(ForumTopicPermissionActions.Update)
				.Add(ForumTopicPermissionActions.UpdatePoll)
				.Add(ForumTopicPermissionActions.Tag)
				.Add(ForumTopicPermissionActions.VotePoll);

			permissions.Add(users);

			// moderators permissions
			var moderators = new ForumPermission
			{
				Role = new UserRole { Title = Roles.Moderators }
			};

			moderators.Action = moderators.Action.Max<ForumPermissionActions>();
			moderators.PostAction = moderators.Action.Max<ForumPostPermissionActions>();
			moderators.TopicAction = moderators.Action.Max<ForumTopicPermissionActions>();

			permissions.Add(moderators);

			// administrators permissions
			var administrators = new ForumPermission
			{
				Role = new UserRole { Title = Roles.Administrators }
			};

			administrators.Action = administrators.Action.Max<ForumPermissionActions>();
			administrators.PostAction = administrators.Action.Max<ForumPostPermissionActions>();
			administrators.TopicAction = administrators.Action.Max<ForumTopicPermissionActions>();

			permissions.Add(administrators);

			return permissions;
		}

		/// <summary>
		/// Creates the forum permission.
		/// </summary>
		/// <returns></returns>
		public ForumPermission Create()
		{
			return new ForumPermission();
		}

		/// <summary>
		/// Inserts the specified forum permission.
		/// </summary>
		/// <param name="permission">The permission.</param>
		public void Insert(ForumPermission permission)
		{
			this.ForumPermissionRepository.Insert(permission);
		}

		/// <summary>
		/// Inserts the specified forum permission.
		/// </summary>
		/// <param name="permission">The permission.</param>
		/// <param name="value">The value.</param>
		public void Insert(ForumPermission permission, ForumPermissionCreate value)
		{
			value.Validate();

			var role = UserRoleService.GetBy(new UserRoleSpecification
			{
				Title = value.Role
			});

			if (role == null)
			{
				return;
			}

			permission.ForumId = value.ForumId;
			permission.Role = role;
			permission.Action = (ForumPermissionActions)value.Actions.Value();
			permission.PostAction = (ForumPostPermissionActions)value.PostsActions.Value();
			permission.TopicAction = (ForumTopicPermissionActions)value.TopicsActions.Value();

			this.Insert(permission);
		}

		/// <summary>
		/// Updates the specified forum permission.
		/// </summary>
		/// <param name="permission">The permission.</param>
		public void Update(ForumPermission permission)
		{
			this.ForumPermissionRepository.Update(permission);
		}

		/// <summary>
		/// Updates the specified forum permission.
		/// </summary>
		/// <param name="permission">The permission.</param>
		/// <param name="value">The value.</param>
		public void Update(ForumPermission permission, ForumPermissionUpdate value)
		{
			value.Validate();

			permission.Action = (ForumPermissionActions)value.Actions.Value();
			permission.PostAction = (ForumPostPermissionActions)value.PostsActions.Value();
			permission.TopicAction = (ForumTopicPermissionActions)value.TopicsActions.Value();

			this.Update(permission);
		}

		/// <summary>
		/// Deletes the specified forum permission.
		/// </summary>
		/// <param name="permission">The permission.</param>
		public void Delete(ForumPermission permission)
		{
			this.ForumPermissionRepository.Delete(permission);
		}
	}
}